#include "Logger.h"
#include "Utilities.h"

namespace Nezha
{

	static LoggerOutput* gsLoggerOutputs[Logger::MAX_OUTPUT_TYPE] = {NULL};
	static int gsOutputFlag = Logger::CONSOLE;
	static Logger::Level gsLoggerFilter = Logger::LL_DEBUG;

	int __Logger_getBitIndex(Logger::OutputType ot)
	{
		int index = 0;
		int n = 1;

		while(index < Logger::MAX_OUTPUT_TYPE)
		{
			if(n & ot)
			{
				break;
			}

			++index;
			n <<= 1;
		}

		return index;
	}

	void Logger::SetLoggerOutput(Logger::OutputType ot, LoggerOutput* lo)
	{
		int index = __Logger_getBitIndex(ot);

		if(index < Logger::MAX_OUTPUT_TYPE)
		{
			gsLoggerOutputs[index] = lo;
		}
	}

	void Logger::SetOutputFlag(int flag)
	{
		gsOutputFlag = flag;
	}

	int Logger::GetOutputFlag()
	{
		return gsOutputFlag;
	}

	void Logger::SetLoggerFilter(Logger::Level lv)
	{
		gsLoggerFilter = lv;
	}

	// for avoid stack costing
#define VA_LIST_FILL_N_POST(lv)\
	va_list argLst;\
	char buffer[MAX_NEZHA_LOGGER_BUFFER];\
	va_start(argLst, info);\
	vsprintf(buffer, info, argLst);\
	va_end(argLst);\
	str += buffer;\
	int flag = 1;\
	for(int i=0;i<Logger::MAX_OUTPUT_TYPE;i++){\
		if((gsOutputFlag & flag) && gsLoggerOutputs[i]){\
			gsLoggerOutputs[i]->post(str, lv);\
			flag <<= 1;\
		}}

	void Logger::Debug(const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_DEBUG)
			return;

		String str;
		GetLocalTimeString(str);

		str += " Debug ";

		VA_LIST_FILL_N_POST(Logger::LL_DEBUG);
	}

	void Logger::Log(const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_INFO)
			return;

		String str;
		GetLocalTimeString(str);

		str += " Info ";
		
		VA_LIST_FILL_N_POST(Logger::LL_INFO);
	}

	void Logger::Warning(const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_WARNING)
			return;

		String str;
		GetLocalTimeString(str);

		str += " Warning ";

		VA_LIST_FILL_N_POST(Logger::LL_WARNING);
	}

	void Logger::Error(const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_ERROR)
			return;

		String str;
		GetLocalTimeString(str);

		str += " Error ";

		VA_LIST_FILL_N_POST(Logger::LL_ERROR);
	}

	void Logger::Debug2(int outputFlag, const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_DEBUG)
			return;

		int prevFlags = gsOutputFlag;
		gsOutputFlag = outputFlag;

		String str;
		GetLocalTimeString(str);

		str += " Debug ";

		VA_LIST_FILL_N_POST(Logger::LL_DEBUG);

		gsOutputFlag = prevFlags;
	}

	void Logger::Log2(int outputFlag, const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_INFO)
			return;

		int prevFlags = gsOutputFlag;
		gsOutputFlag = outputFlag;

		String str;
		GetLocalTimeString(str);

		str += " Info ";

		VA_LIST_FILL_N_POST(Logger::LL_INFO);

		gsOutputFlag = prevFlags;
	}

	void Logger::Warning2(int outputFlag, const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_WARNING)
			return;

		int prevFlags = gsOutputFlag;
		gsOutputFlag = outputFlag;

		String str;
		GetLocalTimeString(str);

		str += " Warning ";

		VA_LIST_FILL_N_POST(Logger::LL_WARNING);

		gsOutputFlag = prevFlags;
	}

	void Logger::Error2(int outputFlag, const char* info, ...)
	{
		if((int)gsLoggerFilter > (int)LL_ERROR)
			return;

		int prevFlags = gsOutputFlag;
		gsOutputFlag = outputFlag;

		String str;
		GetLocalTimeString(str);

		str += " Error ";

		VA_LIST_FILL_N_POST(Logger::LL_ERROR);

		gsOutputFlag = prevFlags;
	}


#undef VA_LIST_FILL_N_POST

}